﻿
#include <ctime>
#include <iostream>

using namespace std;

#include <thread>
#include <random>
#include <string>
#include <vector>
#include <algorithm>

void RandomTestBeforeCpp11();

void RandomTestAfterCpp11();

template<typename T>
class Makefinal {
    friend T;

private:
    Makefinal() {}

    ~Makefinal() {}
};

class FinalClass2 : virtual public Makefinal<FinalClass2> {
public:
    FinalClass2() {}

    ~FinalClass2() {}
};

static std::vector<char> array_pwd{
        '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
        'A', 'B', 'C', 'D', 'E', 'F', 'G',
        'H', 'I', 'J', 'K', 'L', 'M', 'N',
        'O', 'P', 'Q', 'R', 'S', 'T',
        'U', 'V', 'W', 'X', 'Y', 'Z',
        'a', 'b', 'c', 'd', 'e', 'f', 'g',
        'h', 'i', 'j', 'k', 'l', 'm', 'n',
        'o', 'p', 'q', 'r', 's', 't',
        'u', 'v', 'w', 'x', 'y', 'z',
        '-', '@', '#', '!', '%', '&', '_'};

/**
 * 打乱字符数组顺序
 * @param players
 * @param times
 */
void shuffle_test(vector<char> &players, int times) {
    for (size_t i = 0; i < times; i++) {
        std::shuffle(players.begin(), players.end(),
                     std::mt19937{std::random_device{}()});
    }
}

/**
 * 生成密码
 * @param len     密码长度
 * @param filter  不包含的字符集合
 * @return 生成的随机密码
 */
auto generatePassword(int len, const std::string &filter) -> std::string {
    std::mt19937 sd{std::random_device{}()};
    std::uniform_int_distribution<int> distribution{0, (int) array_pwd.size() - 1};

    // 对密码字符数组打乱n次,这样处理只是为了更加随机
    // shuffle_test(array_pwd, 2);
    static std::vector<char> result;
    result.resize(len + 1, '\0');
    char ch{'\0'};
    for (int i = 0; i < len; ++i) {
        GEN_CH:
        ch = array_pwd[distribution(sd)];
        if (filter.find(ch) != std::string::npos) {
            goto GEN_CH;
        }
        result[i] = ch;
    }
    return result.data();
}

int main(int argc, char const *argv[]) {
// RandomTestAfterCpp11();

    for (int i = 0; i < 10; ++i) {
        std::cout << generatePassword(10, "!%*()&=+@#") << std::endl;
    }
    return 0;
}

void RandomTestBeforeCpp11() {
    srand(1645683421); // 随机数种子不变，每次获取的随机数一样

    for (int i = 0; i < 10; ++i) {
        cout << "Get Random " << rand() << endl;
    }
}

void RandomTestAfterCpp11() {
    default_random_engine engine;               // same as "mt19937 eng;"
    random_device sd;                           //生成random_device对象sd做种子
    minstd_rand linearRan(sd());                //使用种子初始化linear_congruential_engine对象，
    // 为的是使用它来做我们下面随机分布的种子以输出多个随机分布.
    // 注意这里要使用()操作符，因为minst_rand()接受的是一个值（你用srand也是给出这样的一个值）
    uniform_int_distribution<int> dis1(0, 1);   //生成01序列
    for (int i = 0; i < 50; i++) {
        // 使用linear engine做种子，注意这里传入的不是一个值而是一个引擎:
        //【随机分布函数需要传入一个随机数引擎作为参数，其实random_device也是一个引擎，这里把sd传入也不会出错】
        cout << dis1(linearRan) << "\t" << dis1(engine) << endl;
    }

    // 正态分布, 均值10, 标准差3
    normal_distribution<double> distrN(10.0, 3);
    for (int i = 0; i < 50; i++) {
        // 仿函数，参数为 engine
        cout << distrN(linearRan) << "\t" << distrN(engine) << endl;
    }
}
